//
//  ChatMessageView.swift
//  Telegram-Mac
//
//  Created by keepcoder on 08/09/16.
//  Copyright © 2016 Telegram. All rights reserved.
//

import Cocoa
import TGUIKit
import SwiftSignalKit
import TelegramCore
import Postbox


class ChatMessageView: ChatRowView, ModalPreviewRowViewProtocol {
    
    class ActionButton: TextButton {
        
        var urlView: ImageView?
        
        required init(frame frameRect: NSRect) {
            super.init(frame: frameRect)
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        func set(isExternalUrl: Bool, color: NSColor) {
            if isExternalUrl {
                let current: ImageView
                if let view = self.urlView {
                    current = view
                } else {
                    current = ImageView()
                    addSubview(current)
                    self.urlView = current
                }
                current.image = NSImage.init(named: "Icon_InlineBotUrl")?.precomposed(color)
                current.sizeToFit()
            } else if let view = self.urlView {
                view.removeFromSuperview()
                self.urlView = nil
            }
            needsLayout = true
        }
        
        override func layout() {
            super.layout()
            if let view = urlView {
                view.setFrameOrigin(NSMakePoint(frame.width - view.frame.width - 5, 5))
            }
        }
    }
    
    class AdSettingsView : View {
        private let close: ImageButton = ImageButton()
        private var more: ImageButton?
        private let separator = View()
        
        private weak var item: ChatMessageItem?
        
        required init(frame frameRect: NSRect) {
            super.init(frame: frameRect)
            
            addSubview(close)
            addSubview(separator)
            
            close.scaleOnClick = true
            close.autohighlight = false
            
            close.set(handler: { [weak self] _ in
                if let item = self?.item {
                    item.webpageLayout?.premiumBoarding()
                }
            }, for: .Click)

        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        override func layout() {
            super.layout()
            close.setFrameOrigin(.zero)
            separator.frame = NSMakeRect(6, close.frame.maxY + 3, frame.width - 12, .borderSize)
            more?.setFrameOrigin(NSMakePoint(0, close.frame.maxY + 6))

        }
        
        func update(_ item: ChatMessageItem, animated: Bool) {
            self.item = item
            backgroundColor = theme.colors.background
            
            separator.backgroundColor = theme.colors.grayIcon.withAlphaComponent(0.4)

            close.set(image: NSImage(resource: .iconAdHide).precomposed(theme.colors.grayIcon), for: .Normal)
            close.sizeToFit(.zero, NSMakeSize(30, 30), thatFit: true)
            separator.isHidden = !item.isFragmentAd
            
            
            if item.isFragmentAd {
                let current: ImageButton
                if let view = self.more {
                    current = view
                } else {
                    current = ImageButton(frame: NSMakeRect(0, 30, 30, 30))
                    current.scaleOnClick = true
                    current.autohighlight = false

                    self.more = current
                    addSubview(current)
                    
                   
                    
                }
                current.removeAllHandlers()
                current.set(handler: { [weak item] control in
                    if let item = item, let event = NSApp.currentEvent {
                        _ = item.menuItems(in: .zero).startStandalone(next: { [weak control] items in
                            if let control = control {
                                let menu = ContextMenu()
                                menu.items = items
                                AppMenu.show(menu: menu, event: event, for: control)
                            }
                        })
                    }
                }, for: .Down)
                current.set(image: NSImage(resource: .iconAdMore).precomposed(theme.colors.grayIcon), for: .Normal)
                current.sizeToFit(.zero, NSMakeSize(30, 30), thatFit: true)
            } else if let view = self.more {
                performSubviewRemoval(view, animated: animated)
                self.more = nil
            }
        }
    }
    
    
    func fileAtPoint(_ point: NSPoint) -> (QuickPreviewMedia, NSView?)? {
        if let webpageContent = webpageContent {
            return webpageContent.fileAtPoint(convert(point, from: self))
        }
        
        return nil
    }
    
    override func forceClick(in location: NSPoint) {
        if previewMediaIfPossible() {
            
        } else {
            super.forceClick(in: location)
        }
    }
    
    override func previewMediaIfPossible() -> Bool {
        return webpageContent?.previewMediaIfPossible() ?? false
    }
    
    private var text:FoldingTextView?

    private(set) var webpageContent:WPContentView?
    private var actionButton: ActionButton?
    
    
    private var adSettingView: AdSettingsView?
    

    override func draw(_ dirtyRect: NSRect) {
        
        // Drawing code here.
    }
    
    required init(frame frameRect: NSRect) {
        
        super.init(frame: frameRect)
       // self.layerContentsRedrawPolicy = .never
    }
    
    
    override func layout() {
        super.layout()
       
    }
    
    func webpageFrame(_ item: ChatMessageItem) -> NSRect {
        guard let item = self.item as? ChatMessageItem else {
            return .zero
        }
        let maxY: CGFloat

        if item.webpageAboveContent {
            maxY = 1
        } else {
            maxY = textFrame(item).maxY + item.defaultContentInnerInset
        }
        if let webpageLayout = item.webpageLayout {
            let size = webpageLayout.size
            return CGRect(origin: NSMakePoint(0, maxY), size: size)
        }
        return .zero
    }
    
    func textFrame(_ item: ChatMessageItem) -> NSRect {
        guard let item = self.item as? ChatMessageItem else {
            return .zero
        }
        let maxY: CGFloat

        if item.webpageAboveContent, item.webpageLayout != nil {
            maxY = webpageFrame(item).maxY + item.defaultContentInnerInset - 2
        } else {
            maxY = 0
        }
        return CGRect(origin: NSMakePoint(0, maxY), size: item.textLayout.size)

    }
    
    func adSettingFrame(_ item: ChatMessageItem) -> NSRect {
        let webpage = webpageFrame(item)
        var rect = NSMakeRect(webpage.maxX + contentFrame(item).minX + 10, contentFrame(item).minY + webpage.minY, 30, item.isFragmentAd ? 69 : 30)
        if item.isBubbled {
            rect.origin.x += 10
            rect.origin.y = bubbleFrame(item).minY
        }
        return rect
    }
    
    override func updateLayout(size: NSSize, transition: ContainedViewLayoutTransition) {
        super.updateLayout(size: size, transition: transition)
        guard let item = self.item as? ChatMessageItem else {
            return
        }
        if let webpageContent = webpageContent {
            transition.updateFrame(view: webpageContent, frame: webpageFrame(item))
        }
        
        if let text = self.text {
            transition.updateFrame(view: text, frame: textFrame(item))
        }
        
        if let actionButton = actionButton {
            var add = item.additionalLineForDateInBubbleState ?? 0
            if !item.isBubbled {
                add = 0
            }
            let contentRect = self.contentFrame(item)
            transition.updateFrame(view: actionButton, frame: CGRect(origin: NSMakePoint(contentRect.minX, contentRect.maxY - actionButton.frame.height + add), size: actionButton.frame.size))
        }
        
        if let adSettingView {
            transition.updateFrame(view: adSettingView, frame: adSettingFrame(item))
        }
    }

    override func canStartTextSelecting(_ event: NSEvent) -> Bool {
        if let superTextView = text?.superview {
            if let webpageContent = webpageContent {
                return !NSPointInRect(superTextView.convert(event.locationInWindow, from: nil), webpageContent.frame)
            }
            return true
        }
        return false
    }
    
    override var selectableTextViews: [TextView] {
        var views:[TextView] = super.selectableTextViews + (text?.textViews ?? [])
        if let webpage = webpageContent {
            views += webpage.selectableTextViews
        }
        return views
    }
    
    override func updateMouse(animated: Bool) {
        super.updateMouse(animated: animated)
        webpageContent?.updateMouse()
    }
    
    override func canMultiselectTextIn(_ location: NSPoint) -> Bool {
        let point = self.contentView.convert(location, from: nil)
        return true
    }
    
    override func focusAnimation(_ innerId: AnyHashable?, text: String?) {
        super.focusAnimation(innerId, text: text)
        
        guard let item = item as? ChatRowItem else {
            return
        }
        if let text = text, !text.isEmpty {
            self.text?.highlight(text: text, color: item.presentation.colors.focusAnimationColor)
        }
    }


    override func set(item:TableRowItem, animated:Bool = false) {
        let previous = self.item as? ChatMessageItem
        super.set(item: item, animated: animated)

        if let item = item as? ChatMessageItem {
            
            let isEqual = previous?.textLayout.string == item.textLayout.string
            if isEqual, let view = self.text {
                view.update(layout: item.textLayout, animated: animated)
            } else {
                if let view = self.text {
                    performSubviewRemoval(view, animated: animated)
                }
                let current: FoldingTextView = FoldingTextView(frame: textFrame(item))
                current.update(layout: item.textLayout, animated: false)
                
                current.revealBlockAtIndex = { [weak self] index in
                    if let item = self?.item as? ChatMessageItem {
                        item.revealBlockAtIndex(index)
                    }
                }
                
                self.text = current
                addSubview(current)
                
                if animated {
                    current.layer?.animateAlpha(from: 0, to: 1, duration: 0.2)
                }
            }
            
            if let webpageLayout = item.webpageLayout {
                let updated = webpageContent == nil || !webpageContent!.isKind(of: webpageLayout.viewClass())
                let current: WPContentView
                if !updated, let view = self.webpageContent {
                    current = view
                } else {
                    if let view = self.webpageContent {
                        performSubviewRemoval(view, animated: animated)
                    }
                    let vz = webpageLayout.viewClass() as! WPContentView.Type
                    current = vz.init()
                    current.frame = webpageFrame(item)
                    self.webpageContent = current
                    addSubview(current)
                    if animated {
                        current.layer?.animateAlpha(from: 0, to: 1, duration: 0.2)
                    }
                }
                
                current.update(with: webpageLayout, animated: animated)
            } else if let view = webpageContent {
                performSubviewRemoval(view, animated: animated)
                webpageContent = nil
            }
            if let text = item.actionButtonText {
                var isNew = false
                if actionButton == nil {
                    actionButton = ActionButton(frame: .zero)
                    actionButton?.layer?.cornerRadius = .cornerRadius
                    actionButton?.disableActions()
                    actionButton?.set(font: .normal(.text), for: .Normal)
                    self.rowView.addSubview(actionButton!)
                    isNew = true
                }
                actionButton?.set(isExternalUrl: item.hasExternalLink, color: item.wpPresentation.activity.main)
                actionButton?.scaleOnClick = true
                actionButton?.removeAllHandlers()
                actionButton?.set(handler: { [weak item] _ in
                    item?.invokeAction()
                }, for: .Click)
                actionButton?.set(text: text, for: .Normal)
                actionButton?.set(color: item.wpPresentation.activity.main, for: .Normal)
                actionButton?.set(background: item.wpPresentation.activity.main.withAlphaComponent(0.1), for: .Normal)
                _ = actionButton?.sizeToFit(NSZeroSize, NSMakeSize(item.actionButtonWidth, 36), thatFit: true)
                if animated, isNew {
                    actionButton?.layer?.animateScaleCenter(from: 0.1, to: 1, duration: 0.2, timingFunction: .easeOut)
                    actionButton?.layer?.animateAlpha(from: 0, to: 1, duration: 0.2)
                }
            } else {
                if let view = actionButton {
                    performSubviewRemoval(view, animated: animated)
                    actionButton = nil
                }
            }
                        
            if let adAttribute = item.message?.adAttribute {
                let current: AdSettingsView
                if let view = self.adSettingView {
                    current = view
                } else {
                    current = AdSettingsView(frame: adSettingFrame(item))
                    self.adSettingView = current
                    self.rowView.addSubview(current)
                }
                current.update(item, animated: animated)
                current.layer?.cornerRadius = current.frame.width / 2
            } else if let view = self.adSettingView {
                performSubviewRemoval(view, animated: animated)
                self.adSettingView = nil
            }

        }

    }
    
    override func updateAnimatableContent() {
        super.updateAnimatableContent()
    }
    
    override func clickInContent(point: NSPoint) -> Bool {
        guard let item = item as? ChatMessageItem else {return true}
        
        if let text = self.text {
            return text.clickInContent(point: point)
        } else {
            return false
        }
    }
    
    override func interactionContentView(for innerId: AnyHashable, animateIn: Bool ) -> NSView {
        if let webpageContent = webpageContent {
            return webpageContent.interactionContentView(for: innerId, animateIn: animateIn)
        }
        return self
    }
    

    override func convertWindowPointToContent(_ point: NSPoint) -> NSPoint {
        let main = super.convertWindowPointToContent(point)
        
        if let webpageContent = webpageContent, NSPointInRect(main, webpageContent.frame) {
            return webpageContent.convertWindowPointToContent(point)
        } else {
            return main
        }
    }
    
    override func storyControl(_ storyId: StoryId) -> NSView? {
        if let item = item as? ChatRowItem {
            if item.message?.storyAttribute?.storyId == storyId {
                return super.storyControl(storyId)
            } else {
                return self.webpageContent?.mediaContentView ?? super.storyControl(storyId)
            }
        }
        return nil
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}
